<template>
  <div class="container">
    <div class="init-chat" v-if="!startChat">
      <div class="title"></div>

      <div class="blank"></div>

      <div class="ask-area">
        <div>
          <el-input
              class="chat-box"
              type="textarea"
              :rows="6"
              resize="none"
              placeholder="有什么问题尽管问......"
              @keyup.enter.native="sendQuestion"
              v-model="userQuestion">
          </el-input>
        </div>
        <el-button icon="el-icon-s-promotion" type="primary" class="submit-btn" size="medium" @click="sendQuestion"  @keyup.enter.native="sendQuestion">
          发送
        </el-button>
      </div>

      <div class="sample-input">
        <div class="single-sample" v-for="(item,index) in sampleList" :key="index"
             @click="sendQuestionUseDefault(item)">{{ item }}
        </div>
      </div>
    </div>
    <div class="continue-chat" v-else>
      <el-card class="chat-card">
        <div class="chat-area">
          <div class="single-chat" v-for="(item,index) in chatHistory" :key="index">
            <div class="model-answer" v-if="item.role === 0">
              <img class="model-avatar" src="https://service-plat.oss-cn-beijing.aliyuncs.com/model_avatar.png" alt=""/>
              <div class="markdown-body" v-html="item.content"></div>
            </div>
            <div class="user-ask" v-else>
              <div class="user-ask-inner">
                <div class="user-content">{{ item.content }}</div>
                <el-avatar class="user-avatar"
                           src="https://service-plat.oss-cn-beijing.aliyuncs.com/avatar.jpg"></el-avatar>
              </div>
            </div>
          </div>
        </div>

        <div class="more-ask-area">
          <el-input
              type="textarea"
              :rows="6"
              resize="none"
              placeholder="还有什么问题？尽管问!"
              v-model="userQuestion"
              @keyup.enter.native="sendQuestion"
          >
          </el-input>
          <el-button icon="el-icon-s-promotion" type="primary" size="small" class="more-submit-btn"
                     @click="sendQuestion">
            发送
          </el-button>
        </div>
      </el-card>
    </div>
  </div>
</template>

<script>
import {io} from "socket.io-client";
import hljs from "highlight.js";

export default {
  name: 'IntelligentQA',
  data() {
    return {
      tmpAnswer: '',
      nowHTML: '',
      userQuestion: '',
      // 是否开启了对话 用来控制当前展示哪个页面
      startChat: false,
      talkTitle: [
        '阅书万卷，我是你的知识宝典',
        '一触即发，我是你的灵感引擎',
        '跨界协作，我是你的智能助手',
        '有问必答，我是你的学习搭档',
      ],
      // 循环打字的定时器id
      sayWordId: undefined,
      sampleList: [
        '🌳橡胶树石细胞是什么样子？',
        '🦠当前细胞分割存在的问题有哪些？',
        '🔬所提出的CGWO-LWNet有哪些亮点？',
        '🗊更多'
      ],
      // 聊天记录 role==0代表大模型 1代表用户
      chatHistory: [],
      // socketio
      socket: null,
      // 如果用户使用了默认的内容 就会改变这个值为默认内容
      defaultQuestion: undefined
    }
  },
  mounted() {
    this.sayWord();
    this.initSocket();
  },
  beforeDestroy() {
    // 离开时断开Socketio连接
    if (this.socket !== null) {
      this.socket.disconnect();
    }
  },
  methods: {
    initSocket() {
      this.socket = io('http://yiyuy.mynatapp.cc/chat', {
        transports: ['websocket']
      })

      this.socket.on('disconnect', (msg) => {
        this.socket.disconnect()
      })

      // 监听服务器那边返回的消息
      this.socket.on('server_response', (message) => {
        // 收到服务器推送的消息，可以跟进自身业务进行操作
        if (message.data === '[over]') {
          this.socket.disconnect();
          this.socket = undefined;
        } else {
          this.tmpAnswer += message.data;
          this.mdToHtml(this.tmpAnswer, (html) => {
            this.nowHTML = html;
          })
        }
      })
    },
    // 将md转化为html
    mdToHtml(content, callback) {
      import('markdown-it').then(module => {
        const md = module.default('commonmark', {
          highlight: function (str, lang) {
            if (lang && hljs.getLanguage(lang)) {
              try {
                return '<pre class="hljs"><code>' +
                    hljs.highlight(lang, str, true).value +
                    '</code></pre>';
              } catch (__) {
              }
            }

            return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
          }
        });
        callback(md.render(content));
      });
    },
    sayWord() {
      const text = document.querySelector('.title');
      const txt = this.talkTitle

      var index = 0;
      var xiaBiao = 0;
      var huan = true;

      this.sayWordId = setInterval(function () {

        if (huan) {
          if (index >= 9) {
            text.innerHTML = txt[xiaBiao].slice(0, 9) + '<font color="#6495ed">' + txt[xiaBiao].slice(9, ++index) + '</font>';
          } else {
            text.innerHTML = txt[xiaBiao].slice(0, ++index);
          }
        } else {
          if (index >= 9) {
            text.innerHTML = txt[xiaBiao].slice(0, 9) + '<font color="#6495ed">' + txt[xiaBiao].slice(9, index--) + '</font>';
          } else {
            text.innerHTML = txt[xiaBiao].slice(0, index--);
          }
        }

        if (index === txt[xiaBiao].length + 3) {
          huan = false;
        } else if (index < 0) {
          index = 0;
          huan = true;
          xiaBiao++;
          if (xiaBiao >= txt.length) {
            xiaBiao = 0;
          }
        }

      }, 180)
    },
    // 使用下方自带的内容询问大模型
    sendQuestionUseDefault(content) {
      this.defaultQuestion = content
      this.sendQuestion();
    },
    sendQuestion() {
      this.startChat = true
      clearInterval(this.sayWordId)

      // 如果用户输入内容为空
      let question = '';
      if (this.userQuestion.length <= 0) {
        // 但是使用了默认内容
        if (this.defaultQuestion !== undefined) {
          question = this.defaultQuestion
          this.defaultQuestion = undefined
        } else {
          this.$message.warning('请先输入内容')
          return;
        }
      } else {
        question = this.userQuestion
        this.userQuestion = ''
      }

      this.startChat = true

      // 关闭循环打字机
      if (this.sayWordId !== undefined) {
        clearInterval(this.sayWordId)
      }

      // 把用户问题加入历史记录 同时清空大模型回答内容
      this.chatHistory.push({
        role: 1,
        content: question
      })

      // 加入一条大模型的回答内容 开始构造流式回答
      // answer代表chatHistory中的值 是经过markdown处理后的
      // tmpAnswer 只是一个临时的值 用来拼接完整的大模型回复
      let answer = ''
      this.tmpAnswer = ''
      this.nowHTML = ''
      this.chatHistory.push({
        role: 0,
        content: ''
      })

      // 做到打字机效果
      let that = this
      setInterval(function () {
        let len = that.chatHistory.length;
        if (that.nowHTML.length > answer.length) {
          let nowLen = answer.length;
          if (that.nowHTML[nowLen] === '<') {
            while (that.nowHTML[nowLen] !== '>') {
              nowLen++;
            }
          }
          answer = that.nowHTML.slice(0, nowLen + 1);
          that.chatHistory[len - 1].content = answer;
        }
      }, 40)
      this.socket.emit('start_chat', {question: question,username: sessionStorage.getItem('username')})
    }
  }
}
</script>

<style lang="less" scoped>
@keyframes MoveIn {
  0% {
    opacity: 0;
    transform: translateY(12px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.container {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  animation: MoveIn 0.5s ease-in-out;

  .init-chat {
    width: 60%;
    height: 50%;
    display: flex;
    flex-direction: column;
    align-items: center;

    .title {
      height: 40px;
      font-size: 30px;
      font-weight: bold;
    }

    .blank {
      height: 30px;
    }

    .ask-area {
      width: 100%;
      position: relative;

      /deep/ .el-textarea__inner {
        background-color: #fff;
        border-radius: 20px;
        padding-top: 10px;
        padding-bottom: 10px;
        font-size: 17px;
      }

      .submit-btn {
        position: absolute;
        right: 20px;
        bottom: 10px;
      }
    }

    .sample-input {
      height: 50px;
      width: 100%;
      margin-top: 20px;
      display: flex;
      justify-content: space-between;
      align-items: center;

      .single-sample {
        padding: 10px 14px;
        border-radius: 12px;
        height: 40px;
        max-width: 100%;
        text-overflow: ellipsis;
        overflow: hidden;
        white-space: nowrap;
        box-sizing: border-box;
        font-size: 14px;
        cursor: pointer;
        border: .5px solid rgba(0, 0, 0, .13);
        animation: fade-in-4d8dc56a .3s cubic-bezier(.4, 0, .2, 1) forwards;
        transition: background-color .3s cubic-bezier(.36, .66, .04, 1);
        color: rgba(0, 0, 0, .6);
        text-decoration: none;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      .single-sample:hover {
        background-color: #F7F7F7;
      }
    }
  }

  .continue-chat {
    width: 100%;
    height: 100%;

    .chat-card {
      margin: 20px auto;
      height: 90%;
      width: 95%;
      border-radius: 10px;
      border: 1px solid #e5e5e5;
      padding: 5px;
      display: flex;
      flex-direction: column;


      /deep/ .el-card__body {
        height: 100%;
      }

      .chat-area {
        width: 100%;
        height: 82.5%;
        overflow-y: auto;

        .single-chat {
          width: 100%;
          animation: MoveIn .3s cubic-bezier(.4, 0, .2, 1) forwards;
          margin-top: 15px;

          .model-answer {
            display: flex;
            align-items: center;
            height: 100%;

            .markdown-body {
              color: #24292f;
              font-size: 14px;
              word-wrap: break-word;
              padding: 10px;
              border-radius: 10px;
              background-color: #f5f7fa;
              border: 1px solid #e5e5e5;
              margin-left: 10px;
            }

            .model-avatar {
              width: 40px;
              height: 40px;
            }
          }

          .user-ask {
            width: 100%;
            align-items: center;
            display: flex;
            justify-content: flex-end;

            .user-ask-inner {
              display: flex;
              align-items: center;

              .user-content {
                padding: 10px;
                border-radius: 10px;
                background-color: #2d65f7;
                color: #ffffff;
              }

              .user-avatar {
                margin-left: 10px;
              }
            }
          }
        }
      }

      .more-ask-area {
        flex: 1;
        border: 1.5px solid #e5e5e5;
        border-radius: 5px;
        position: relative;

        .more-submit-btn {
          position: absolute;
          right: 10px;
          bottom: 10px;
        }
      }
    }
  }
}
</style>